package ae.pcfc.etks.online.itworx.ehs.web.web.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.collections.map.HashedMap;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.MappingJsonFactory;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.RequestContextUtils;

import ae.pcfc.etks.online.common.delegate.UserDelegate;
import ae.pcfc.etks.online.common.vo.ActivityVO;
import ae.pcfc.etks.online.common.vo.SCCompanyVO;
import ae.pcfc.etks.online.common.vo.SearchCriteriaActivityVO;
import ae.pcfc.etks.online.common.vo.UserDetailVO;
import ae.pcfc.etks.online.itworx.ehs.web.common.exception.helper.ExceptionHandlerHelper;
import ae.pcfc.etks.online.itworx.ehs.web.constants.GlobalConstants;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.EHSDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.IMSDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.WorkflowDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.entity.Comment;
import ae.pcfc.etks.online.itworx.ehs.web.entity.OFCDocument;
import ae.pcfc.etks.online.itworx.ehs.web.entity.OFCRequest;
import ae.pcfc.etks.online.itworx.ehs.web.entity.OFCRequestHistory;
import ae.pcfc.etks.online.itworx.ehs.web.entity.Request;
import ae.pcfc.etks.online.itworx.ehs.web.entity.Service;
import ae.pcfc.etks.online.itworx.ehs.web.enums.AmendmentType;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestAction;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestField;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestStatus;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestType;
import ae.pcfc.etks.online.itworx.ehs.web.enums.UserType;
import ae.pcfc.etks.online.itworx.ehs.web.enums.WorkflowDataFields;
import ae.pcfc.etks.online.itworx.ehs.web.exception.CommunicationException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.FNPServiceExpcetion;
import ae.pcfc.etks.online.itworx.ehs.web.exception.IMSException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.InvalidInputException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.SystemException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.WorkFlowException;
import ae.pcfc.etks.online.itworx.ehs.web.model.OFCRequestCreation;
import ae.pcfc.etks.online.itworx.ehs.web.model.RequestSearchCriteria;
import ae.pcfc.etks.online.itworx.ehs.web.util.MailUtility;
import ae.pcfc.etks.online.itworx.ehs.web.util.UtilCommon;
import ae.pcfc.etks.online.web.util.token.SessionToken;

@Controller
@RequestMapping("/client")
public class Customer {

	private WorkflowDelegate workflowDelegate;

	private EHSDelegate ehsDelegate;

	private Map<String, String> generalMap;

	private MailUtility mailUtility;

	private Validator validator;
	
	private IMSDelegate imsDelegate;
	
	private UserDelegate tscUserDelegate;
	
	private static Logger log = LoggerFactory.getLogger(Customer.class);
	
	private SessionToken sessionToken;
	
	@Resource(name = "sessionToken")
	public void setSessionToken(SessionToken sessionToken) 
	{
		this.sessionToken = sessionToken;
	}

	@SuppressWarnings("unused")
	private ResourceBundleMessageSource messageSource;

	/**
	 * @param messageSource
	 *            the messageSource to set
	 */
	@Resource(name = "messageSource")
	public void setMessageSource(ResourceBundleMessageSource messageSource) {
		this.messageSource = messageSource;
	}
	
	@Resource(name = "imsDelegate")
	public void setImsDelegate(IMSDelegate imsDelegate) {
		this.imsDelegate = imsDelegate;
	}

	@Resource(name = "validator")
	public void setValidator(Validator validator) {
		this.validator = validator;
	}

	@InitBinder
	public void initBinder(WebDataBinder binder, Locale locale) {
		binder.setValidator(validator);
	}

	@Resource(name = "mailUtility")
	public void setMailUtility(MailUtility mailUtility) {
		this.mailUtility = mailUtility;
	}

	@Resource(name = "generalMap")
	public void setGeneralMap(Map<String, String> generalMap) {
		this.generalMap = generalMap;
	}

	@Resource(name = "ehsDelegate")
	public void setEhsDelegate(EHSDelegate ehsDelegate) {
		this.ehsDelegate = ehsDelegate;
	}

	public WorkflowDelegate getWorkflowDelegate() {
		return workflowDelegate;
	}

	@Resource(name = "workflowDelegate")
	public void setWorkflowDelegate(WorkflowDelegate workflowDelegate) {
		this.workflowDelegate = workflowDelegate;
	}
	
	@Resource(name = "tscUserDelegate")
	public void setTscDelegate(UserDelegate tscUserDelegate) {
		this.tscUserDelegate = tscUserDelegate;
	}
	// this method return details for both "my requests" and "My inbox"
	@Transactional(readOnly=true)
	@RequestMapping(value = "/viewDetails.htm", method = RequestMethod.GET)
	public String getRequestDetails(Model model,
			@RequestParam(value = "requestId") long requestId, HttpServletRequest request) {
		
		log.debug("Customer.getRequestDetails() - inside the get details method in Officer controller! and requestId = "
						+ requestId);
		OFCRequest ofcRequest = null;
		boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
		String username = "";
		if(isCustomer){
			username = request.getUserPrincipal().getName();
		}else{
			return "redirect:/login.jsp";
		}
		OFCRequestCreation ofcRequestModel = new OFCRequestCreation();
		try {
			// 2- get the Details
			ofcRequest = workflowDelegate.getDetails(requestId, username, false);

			// 3- TODO: put the request Details in the model
		workflowDelegate.getMapper().map(ofcRequest, ofcRequestModel);
		if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
			ofcRequestModel.setAmendmentTypes(AmendmentType.values());
		}
		ofcRequestModel.setServiceName(ofcRequest.getService().getName());
		prepareModelLocations(request, ofcRequestModel);
		prepareModelJson(model, ofcRequestModel.getStatus());
		model.addAttribute(GlobalConstants.OFC_REQUEST_MODEL, ofcRequestModel);
		// TODO: return the model object
		return "client.viewDetails";
		}
		catch(InvalidInputException invalExp) 
		{
			ExceptionHandlerHelper.handleException(invalExp);
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage(invalExp.getErrorCode(), null, RequestContextUtils.getLocale(request)));
			return "redirect:listRequests.htm?type=myRequests";
		}
		catch (Exception ex) {
			log.error("Customer.getRequestDetails() - error happned while getting request Details for request ("+requestId+") with userId ("+username+")",ex);
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("error.generic", null, RequestContextUtils.getLocale(request)));
			return "redirect:listRequests.htm?type=myRequests";
		}
	}

	private void prepareModelLocations(HttpServletRequest request,
			OFCRequestCreation ofcRequestModel) {
		String userName = null;
		if(isOfficerUser(request)){
			userName = request.getParameter(GlobalConstants.USER_ID_ATTRIBUTE);
		}else{
			userName = request.getUserPrincipal().getName();
		}
		if(userName != null 
				&& (RequestStatus.Return_For_Update.equals(ofcRequestModel.getStatus()) 
						|| null == ofcRequestModel.getStatus())){
			UserDetailVO userDetails =  tscUserDelegate.findUserDetailByUserName(userName);
			
	        SCCompanyVO companyInfo  = userDetails.getCompanyVO();//tscClientRegistrationDelegate.findSCCompanyByTrakheesId(userDetails.getTrakheesId());
			ofcRequestModel.setLocations(getTrakeesLocations(companyInfo));
		}
	}
	
	public boolean isOfficerUser(HttpServletRequest request){
		return (request.isUserInRole(GlobalConstants.OFFICER_ROLE)); 
	}

	@Transactional(readOnly = true)
	@RequestMapping(value = "/activeTaskDetails.htm", method = RequestMethod.GET)
	public ModelMap viewActiveTaskDetails(
			@RequestParam(value = "requestId", required = true) Long requestId) {
		log.debug("Customer.viewActiveTaskDetails() -  inside the viewActiveTaskDetails method in Customer controller! and requestId = "
						+ requestId);
		OFCRequest ofcRequest = null;
		try {
			ofcRequest = workflowDelegate.getRequestDetails(requestId);
			// ofcRequest.setSerialNumber(serialNumber);

		} catch (Exception ex) {
			log.error("Customer.viewActiveTaskDetails() -  error while getting active task details for request ("+requestId+")",ex);
		}

		return new ModelMap("ofcRequest", ofcRequest);
	}
	
	@Transactional(readOnly=true)
	@RequestMapping(value = "/create.htm", method = RequestMethod.GET)
	public String setupCreateRequestForm(Model model,
			@RequestParam(value = "type") String requestType,
			@RequestParam(value = "userName", required=false) String userName,
			HttpServletRequest request) {
		
		String loggedInUser = request.getUserPrincipal().getName(); //getRemoteUser();
		String username = "";
		boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
		if(null == loggedInUser){
			return "redirect:/login.jsp";
		}
		
		String officerId = "";
		
		if(isCustomer){
			username = loggedInUser;
		}else{
			//Officer Role
			boolean isOfficer = request.isUserInRole(GlobalConstants.OFFICER_ROLE);
			
			if(isOfficer){
				if(null == userName || userName.trim().equals("")){
					//return  "";
					//TODO: return to the view where officer should select a customer first
					//return "redirect:";
					return "redirect:/officer/selectTksUsers.htm?type="+requestType;
				}else{
					username = userName;
					officerId = loggedInUser;
					//officerId = "somaya.rayan";
				}
			}else{
				return  "redirect:/login.jsp";
			}
				
		}
		
		UserDetailVO userDetails =  tscUserDelegate.findUserDetailByUserName(username);

		SCCompanyVO companyInfo  = userDetails.getCompanyVO();// tscClientRegistrationDelegate.findSCCompanyByTrakheesId(userDetails.getTrakheesId());
        
        SearchCriteriaActivityVO searchCriteriaActivityVO = new SearchCriteriaActivityVO();
        String trakheesId = userDetails.getTrakheesId();
        searchCriteriaActivityVO.setTrakheesID(trakheesId);
        
        String[] messageArgs = new String[1];
        messageArgs[0] = trakheesId;
        if(workflowDelegate.getActiveRequestSize(trakheesId) > 0){
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("error.ofcRequestModel.activeRequest", messageArgs, RequestContextUtils.getLocale(request)));
			if(request.isUserInRole(GlobalConstants.CUSTOMER_ROLE))
			{
				return "redirect:/client/listRequests.htm?type=myRequests";
			}
			return "redirect:/officer/viewInbox.htm?type=inbox";
		}
        
        List<ActivityVO> activities = tscUserDelegate.findActivitiesOfClientCompany(searchCriteriaActivityVO);

        String engActivityString = ""; 
        String arActivityString = "";
		
        if(null != activities){
        	for(int index = 0; index < activities.size(); index++){
            	if(index == (activities.size()-1)){
            		engActivityString =  engActivityString.concat(activities.get(index).getActivityDescEn());
                	arActivityString =  arActivityString.concat(activities.get(index).getActivityDescAr());
            	}else{
            		engActivityString =  engActivityString.concat(activities.get(index).getActivityDescEn() + ',');
                	arActivityString =  arActivityString.concat(activities.get(index).getActivityDescAr() + ',');
            	}
            }
			}
		
		OFCRequestCreation ofcRequestModel = new OFCRequestCreation();
		ofcRequestModel = new OFCRequestCreation();
        ofcRequestModel.setLocations(getTrakeesLocations(companyInfo));
		ofcRequestModel.setCreationDate(Calendar.getInstance().getTime());
		ofcRequestModel.setMultipartFiles(new ArrayList<MultipartFile>());
		ofcRequestModel.setCompanyNameEnglish(companyInfo.getStrNameENG());
		ofcRequestModel.setCompanyNameArabic(companyInfo.getStrNameARB());
		ofcRequestModel.setMainEmail(companyInfo.getStrEmail());
		ofcRequestModel.setBusinessUnit(companyInfo.getStrLicenseIssuingAuth());
		ofcRequestModel.setLicenseNumber(companyInfo.getStrLicenseNumber());
                ofcRequestModel.setEngActivity(engActivityString);
                ofcRequestModel.setArActivity(arActivityString);
                ofcRequestModel.setContactPersonName(userDetails.getName());
                ofcRequestModel.setMobile(userDetails.getMobile());
                ofcRequestModel.setAlternativeEmail(userDetails.getEmail());

		
		if (requestType.equals(RequestType.New.name())) {
			ofcRequestModel.setType(RequestType.New);
		} else if (requestType.equals(RequestType.Amendment.name())) {
			ofcRequestModel.setType(RequestType.Amendment);
			ofcRequestModel.setAmendmentTypes(AmendmentType.values());
		} else if (requestType.equals(RequestType.Renewal.name())) {
			ofcRequestModel.setType(RequestType.Renewal);
		}
		ofcRequestModel.setDocumentTypes(ehsDelegate.getAllDocumentType());
		ofcRequestModel.setTrakheesId(userDetails.getTrakheesId());
		ofcRequestModel.setUserId(username);
		ofcRequestModel.setOfficerId(officerId);

		prepareModelJson(model, RequestStatus.Submitted);
		model.addAttribute(GlobalConstants.OFC_REQUEST_MODEL, ofcRequestModel);
		//request.setAttribute("type", ofcRequestModel.getType());

		return "client.create";
	}

	private List<String> getTrakeesLocations(SCCompanyVO companyInfo){
        String facilities = companyInfo.getStrFacilities();
        List<String> locations = new ArrayList<String>();
        if(null != facilities){
        	locations = Arrays.asList(facilities.split(","));
        } else{
        	locations.add("None");
        }
        return locations;
	}

	private void prepareModelJson(Model model, RequestStatus requestStatus) {
		// serialize
		StringWriter sw = new StringWriter(); 
		ObjectMapper mapper = new ObjectMapper();
		MappingJsonFactory jsonFactory = new MappingJsonFactory();
		JsonGenerator jsonGenerator;
		try {
			jsonGenerator = jsonFactory.createJsonGenerator(sw);
			mapper.writeValue(jsonGenerator, ehsDelegate.getAllDocumentTypeByOFCStatus(messageSource.getMessage("document.name.paymentReceipt", null, null), requestStatus).toArray());
			sw.close();
		} catch (IOException e) {
			log.error("Customer.prepareModelJson() - IO error occurred while writting json object",e);
		}
		model.addAttribute(GlobalConstants.DOCUMENT_TYPE_LIST_JSON, sw.toString());
	}

	@Transactional
	@RequestMapping(value = "/create.htm", method = RequestMethod.POST)
	public String createRequest(Model model,
			@ModelAttribute(value = GlobalConstants.OFC_REQUEST_MODEL) @Valid OFCRequestCreation ofcRequestModel,
			BindingResult errors, HttpServletRequest request, Locale locale) {
		
		if(sessionToken.isTokenExist(this.getClass().getName()))
		{
			/****20-march-people went to march for MRF-20130301-DUPLICATE-SUBMISSION*****/
			String username = request.getUserPrincipal().getName();
			UserDetailVO userDetails =  tscUserDelegate.findUserDetailByUserName(username);
			String trakheesId = userDetails.getTrakheesId();
			String[] messageArgs = new String[1];
		    messageArgs[0] = trakheesId;
			if(workflowDelegate.getActiveRequestSize(trakheesId) > 0){
				request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("error.ofcRequestModel.activeRequest", messageArgs, RequestContextUtils.getLocale(request)));
				//Reset Session Token
				sessionToken.resetToken(this.getClass().getName());
				
				if(request.isUserInRole(GlobalConstants.CUSTOMER_ROLE))
				{
					return "redirect:/client/listRequests.htm?type=myRequests";
				}
				return "redirect:/officer/viewInbox.htm?type=inbox";
			}
			
			/**************************March Ends here***********************/
			
			ofcRequestModel.setDocumentTypes(ehsDelegate.getAllDocumentType());	
			errors = validateCreateRequest(ofcRequestModel, errors, locale);
			if (errors.hasErrors()) {
				prepareModelJson(model, RequestStatus.Submitted);
				if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
					ofcRequestModel.setAmendmentTypes(AmendmentType.values());
				}
				prepareModelLocations(request, ofcRequestModel);
				//Reset Session Token
				sessionToken.resetToken(this.getClass().getName());
				return "client.create";
			}
			//ofcRequestModel.setUserId("user");
			//ofcRequestModel.setStatus(RequestStatus.Submitted);
			Service service = Service.ofcService;
			OFCRequest ofcRequest = new OFCRequest();
			Date date = Calendar.getInstance().getTime();
			ofcRequest.setProcessingDate(date);
			if(request.isUserInRole(GlobalConstants.CUSTOMER_ROLE)){
			        ofcRequest.setExecuter(UserType.User);
			}else {
				ofcRequest.setExecuter(UserType.Officer);
			}
			
			ofcRequest.setService(service);
			ofcRequest.setStatus(RequestStatus.Submitted);
			workflowDelegate.getMapper().map(ofcRequestModel, ofcRequest);
			
			try {
				int processID = workflowDelegate.createOFCProcess(ofcRequest);
				ofcRequest.setProcessId(String.valueOf(processID));
				// upload files
				List<MultipartFile> files = ofcRequestModel.getMultipartFiles();
				String mailBody = "";
				if (null != files) {
					for (int i = 0; i < files.size(); i++) {
						FileOutputStream fos = null;
						Date currentDate = new Date();
						try {
							if (null != files.get(i)) {
								// TODO after integration with TSC change
								// uploadedFolder
								// path to take Trakhes ID
								File uploadedFolder = new File(
										generalMap.get("documentLocation")
												+ "/" + ofcRequest.getTrakheesId() + "/"
												+ ofcRequest.getUserId() + "/" + processID);
								if (!uploadedFolder.exists()) {
									uploadedFolder.mkdirs();
								}
								File file = new File(uploadedFolder, files.get(i)
										.getOriginalFilename());
								if (!file.exists()) {
									file.createNewFile();
								}
								fos = new FileOutputStream(file);
								fos.write(files.get(i).getBytes());
								ofcRequest
										.getDocuments()
										.get(i)
										.setDocumentName(
												files.get(i).getOriginalFilename());
								ofcRequest
										.getDocuments()
										.get(i)
										.setDocumentLocation(
												ofcRequest.getTrakheesId()
														+ "/"
														+ ofcRequest
																.getUserId()
																 + "/" + processID
														+ "/"
														+ ofcRequest
																.getDocuments()
																.get(i)
																.getDocumentName());
								if (null == ofcRequest.getDocuments()) {
									ofcRequest
											.setDocuments(new ArrayList<OFCDocument>());
								}
								//mailBody += file.getAbsolutePath() + "<br>";
								//mailBody += "<a href=\"common/download.htm?fileId="+ofcRequest.getDocuments().get(i).getId() + "\""+ofcRequest.getDocuments().get(i).getDocumentName()+"</a><br>";
							}
	
						} catch (Exception ioe) {
							for(int index = i; index < ofcRequest.getDocuments().size(); index++){
								ofcRequest.getDocuments().remove(index);
							}
							request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
							log.error("Customer.createRequest() - error occurred while creating request",ioe);
						} finally {
							if (null != fos) {
								fos.close();
							}
	
						}
					}
					
					
				}
				List<OFCDocument> documents = ofcRequest.getDocuments();
				//List<OFCDocument> newDocuments = ofcRequestModel.getDocuments();
				List<OFCDocument> oldSavedDocuments = ofcRequest.getDocuments();
	
				// To remove deleted javascript document
				if (null != documents) {
					for (OFCDocument ofcDocument : ofcRequest.getDocuments()) {
						if (ofcDocument == null
								|| (ofcDocument.getDocumentLocation() == null
										&& ofcDocument.getDocumentName() == null
										&& ofcDocument.getDocumentType() == null && ofcDocument
										.getId() == 0)) {
							ofcRequest.getDocuments().remove(ofcDocument);
						}
					}
				}
				workflowDelegate.createOFCRequest(ofcRequest);
				if(!workflowDelegate.sendK2Mail(ofcRequest.getProcessId(), ofcRequest.getUserId(), RequestAction.SendMail.getActionName(), ofcRequest, false)){
					request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
					log.error("Customer.createRequest() - error occurred while creating request");

					//Resetting Token
					sessionToken.resetToken(this.getClass().getName());
					return "client.create";
				}
				String URL= "";
				String name = request.getServerName();
				int port = request.getServerPort();
				String ctx = request.getContextPath();
				
				URL = "http://"+name+(port!=0? ":"+port:"")+ctx;
				
				
				//List<OFCDocument> tempDocuments = new ArrayList<OFCDocument>(documents);
				//boolean changedList = tempDocuments.removeAll(oldSavedDocuments);
				if(ofcRequest.getDocuments().size()!=0){
					//Sending Link Email
					for(int doc =0; doc<ofcRequest.getDocuments().size();doc++){
						mailBody += "<a href=\""+URL+"/common/download.htm?fileId="+ofcRequest.getDocuments().get(doc).getId() + "\">"+ofcRequest.getDocuments().get(doc).getDocumentName()+"</a><br>";
					}
				}
				
	//			for(int doc =0; doc<documents.size();doc++){
	//				for(int newDoc =0; newDoc<newDocuments.size();newDoc++)
	//					if(documents.get(doc).getDocumentName().equalsIgnoreCase(newDocuments.get(newDoc).getDocumentName())){
	//						mailBody += "<a href=\""+URL+"/common/download.htm?fileId="+ofcRequest.getDocuments().get(doc).getId() + "\">"+ofcRequest.getDocuments().get(doc).getDocumentName()+"</a><br>";
	//					}
	//			}
				
				Map<String, String> mailMap = new HashedMap();
				mailMap.put(GlobalConstants.CUSTOMER_NAME, ofcRequest.getUserId());
				mailMap.put(GlobalConstants.CUSTOMER_COMPANY, ofcRequest.getCompanyNameEnglish());
				mailMap.put(GlobalConstants.DOCUMENT_URL, mailBody);
				if (!mailBody.isEmpty()) {
					mailUtility.sendMail(null, mailMap, null, GlobalConstants.DOCUMENT_TEMPLATE);
				}
				
	            request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.create", null, RequestContextUtils.getLocale(request)));
			} catch (InvalidInputException e) {
				 request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
				log.error("Customer.createRequest() - invalid input error occurred while creating request",e);
				errors.reject("error.generic");
			}
			catch(WorkFlowException wfExp)
			{
				request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
				log.error("Customer.createRequest() - Workflow error occurred while creating request",wfExp);
				errors.reject("error.generic");
			}catch (Exception e) {
				request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
				log.error("Customer.createRequest() - error occurred while creating request",e);
				errors.reject("error.generic");
			}
	
			if (errors.hasErrors()) {
				prepareModelJson(model, RequestStatus.Submitted);
				if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
					ofcRequestModel.setAmendmentTypes(AmendmentType.values());
				}
				prepareModelLocations(request, ofcRequestModel);
				
				//Resetting Token
				sessionToken.resetToken(this.getClass().getName());
				return "client.create";
			}
	
			if(request.isUserInRole(GlobalConstants.CUSTOMER_ROLE))
			{
				//Resetting Token
				sessionToken.resetToken(this.getClass().getName());
				return "redirect:/client/listRequests.htm?type=myRequests";
			}
			else
			{
				//Resetting Token
				sessionToken.resetToken(this.getClass().getName());
				return "redirect:/officer/viewInbox.htm?type=inbox";
			}
		}
		else
		{
			if(request.isUserInRole(GlobalConstants.CUSTOMER_ROLE))
			{
				return "redirect:/client/listRequests.htm?type=myRequests";
			}
			return "redirect:/officer/viewInbox.htm?type=inbox";
		}
	}

	private BindingResult validateUploadedDocuments(List<MultipartFile> multipartFiles, List<OFCDocument> documents, BindingResult errors, RequestStatus requestStatus){
		if (null != multipartFiles) {
			if (multipartFiles.size() > UtilCommon.getGeneralMapAsInteger(GlobalConstants.MAX_UPLOADED_DOC_COUNT_KEY)) {
				errors.reject("error.ofcRequestModel.multipartFile.numbers");
			}
			for (int i=0; i<multipartFiles.size(); i++) {
				
				if(null != documents && !documents.isEmpty()){
					if((null != documents.get(i).getDocumentLocation() && !documents.get(i).getDocumentLocation().isEmpty()) && (multipartFiles.get(i) == null || multipartFiles.get(i).isEmpty())){
						continue;
					}
				}
				if (multipartFiles.get(i) == null || multipartFiles.get(i).isEmpty()) {
					errors.reject("error.ofcRequestModel.multipartFile.empty");
					break;
				} else if (multipartFiles.get(i).getSize() > UtilCommon.getGeneralMapAsInteger(GlobalConstants.MAX_UPLOADED_DOC_SIZE_KEY)) {
					errors.reject("error.ofcRequestModel.multipartFile.size");
					break;
				} else if (!multipartFiles.get(i).getContentType().equals(
						GlobalConstants.FILE_CONTENT)
						&& 
						!multipartFiles.get(i).getOriginalFilename().toLowerCase().endsWith(".pdf".toLowerCase())) {
					errors.reject("error.ofcRequestModel.multipartFile.extenstion");
					break;

				}
			}
		}else if(null != requestStatus && multipartFiles == null){
			if(requestStatus.equals(RequestStatus.Approved) || requestStatus.equals(RequestStatus.Additional_Payment_Required)){
				errors.reject("error.ofcRequestModel.documentType.reset");
			}
			
		}
		return errors;
	}
	private BindingResult validateCreateRequest(
			OFCRequestCreation ofcRequestModel, BindingResult errors, Locale locale) {

		/*List<MultipartFile> multipartFiles = ofcRequestModel
				.getMultipartFiles();

		if (null != multipartFiles) {
			if (multipartFiles.size() > UtilCommon.getGeneralMapAsInteger(GlobalConstants.MAX_UPLOADED_DOC_COUNT_KEY)) {
				errors.reject("error.ofcRequestModel.multipartFile.numbers");
			}

			for (MultipartFile multipartFile : multipartFiles) {
				if (multipartFile == null || multipartFile.isEmpty()) {
					errors.reject("error.ofcRequestModel.multipartFile.empty");
					break;
				} else if (multipartFile.getSize() > UtilCommon.getGeneralMapAsInteger(GlobalConstants.MAX_UPLOADED_DOC_SIZE_KEY)) {
					errors.reject("error.ofcRequestModel.multipartFile.size");
					break;
				} else if (!multipartFile.getContentType().equals(
						GlobalConstants.FILE_CONTENT)) {
					errors.reject("error.ofcRequestModel.multipartFile.extenstion");
					break;

				}
			}
		}*/
		List<OFCDocument> documents = ofcRequestModel.getDocuments();
		errors = validateUploadedDocuments(ofcRequestModel.getMultipartFiles(), documents, errors, ofcRequestModel.getStatus());

		List<String> documentTypesNames = new ArrayList<String>();
		if (documents != null) {
			for (OFCDocument document : documents) {
				String arabicName = document.getDocumentType()
						.getArabicName();
				String englishName = document.getDocumentType()
						.getEnglishName();
				if (null != arabicName && !arabicName.isEmpty()) {
					documentTypesNames.add(UtilCommon.trim(arabicName));
				} else if (null != englishName
						&& !englishName.isEmpty()) {
					documentTypesNames.add(UtilCommon.trim(englishName));
				}
			}
			
			if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
				String type = ofcRequestModel.getAmendmentType();
				String[] types = null;
				if (type != null) {
					types = type.split(",");
				}
				if (null == types || types.length <= 0) {
					errors.reject("NotEmpty.ofcRequestModel.amendmentType");
				} else {
					if (documents.size() > 0) {
						for (String amendmentType : types) {
							if (amendmentType
									.equals(AmendmentType.Additional_Chemicals
											.getPropertyName())
									&& !documentTypesNames
											.contains(UtilCommon.trim(messageSource.getMessage("document.name.chemical", null, locale)))) {
								errors.reject("error.ofcRequestModel.amendmentType.addChemicals");
							} else if (amendmentType
									.equals(AmendmentType.Additional_Machinery
											.getPropertyName())
									&& !documentTypesNames
											.contains(UtilCommon.trim(messageSource.getMessage("document.name.machinery", null, locale)))) {
								errors.reject("error.ofcRequestModel.amendmentType.addMachinery");
							} else if (amendmentType
									.equals(AmendmentType.Facility_Expansion
											.getPropertyName())
									&& !documentTypesNames
											.contains(UtilCommon.trim(messageSource.getMessage("document.name.bcc", null, locale)))) {
								errors.reject("error.ofcRequestModel.amendmentType.facExpansion");
							} else if (amendmentType
									.equals(AmendmentType.Facility_Modification
											.getPropertyName())
									&& !documentTypesNames
											.contains(UtilCommon.trim(messageSource.getMessage("document.name.bcc", null, locale)))) {
								errors.reject("error.ofcRequestModel.amendmentType.facMod");
							} else if (amendmentType
									.equals(AmendmentType.Licenses_Activity
											.getPropertyName())
									&& !documentTypesNames
											.contains(UtilCommon.trim(messageSource.getMessage("document.name.tradeLicense", null, locale)))) {
								errors.reject("error.ofcRequestModel.amendmentType.licActivity");
							} else if (amendmentType
									.equals(AmendmentType.New_Addition
											.getPropertyName())
									&& !documentTypesNames
											.contains(UtilCommon.trim(messageSource.getMessage("document.name.bcc", null, locale)))) {
								errors.reject("error.ofcRequestModel.amendmentType.newAddition");
							}
							}
						}
					}
				}
		} else if (documents == null && ofcRequestModel.getType().equals(RequestType.Amendment)) {
			errors.reject("NotEmpty.ofcRequestModel.amendmentTypeDocuments");
		}
		if(null != ofcRequestModel.getBcc() && !ofcRequestModel.getBcc().isEmpty()){
			if(!documentTypesNames.contains(messageSource.getMessage("document.name.bcc", null, locale))){
				errors.reject("error.ofcRequestModel.bcc.uploadDocument");
			}
		}
		if (ofcRequestModel.getType().equals(RequestType.Renewal)) {
			if (null == ofcRequestModel.getImsLogId()) {
				errors.reject("NotEmpty.ofcRequestModel.imsLogId");
			} else if (ofcRequestModel.getImsLogId().length() > 10) {
				errors.reject("Length.ofcRequestModel.imsLogId");
			} else if(!UtilCommon.isInteger(ofcRequestModel.getImsLogId())){
					errors.reject("Pattern.userPersonEditInfo.imsLogId");
			}
		}

		return errors;
	}

	@RequestMapping(value = "/listRequests.htm", method = RequestMethod.GET)
	@Transactional(readOnly = true)
	public String listRequests(Model model, HttpServletRequest request,
			@RequestParam(value = "type") String type) {

		// String userId = "user";//should get it from session when integrating
		// with login logic,but now for testing we will add it here
//		HttpSession session = request.getSession();
//		String userId = (String) session
//				.getAttribute(GlobalConstants.USER_NAME_ATTRIBUTE);
		
		boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
		String userId = "";
		if(isCustomer){
			userId = request.getUserPrincipal().getName();
		}else{
			return "redirect:/login.jsp";
		}
		
		System.out
				.println("**************** Cutomer controller ,listRequests, GET");
		// 1- set the default date period
		RequestSearchCriteria searchCriteria = new RequestSearchCriteria();
		Calendar today = Calendar.getInstance();
		today.setTime(new Date());
		searchCriteria.setPageNumber(1);

		// this attribue is added to keep track of which menu item is currently
		// selected!!!!
		searchCriteria.setType(type);

		List<Request> requests = new ArrayList<Request>();
		try {

			long allRequestsSize = workflowDelegate.getAllRequestsSize(userId,
					false, searchCriteria);
			System.out.println("*** allRequestsSize = " + allRequestsSize
					+ " ******");
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = allRequestsSize / pageSize;
			if ((allRequestsSize % pageSize) > 0) {
				totalPages++;
			}
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) allRequestsSize);
			searchCriteria.setFirstAndLastPageFlags();
			searchCriteria.setAssending(true);
			System.out.println("*** totalPages = " + totalPages + " ******");
			requests = workflowDelegate.getAllRequests(userId, false,
					searchCriteria);
			searchCriteria.setSortField(RequestField.CreationDate.getPropertyName());
			System.out.println("requests retuned = " + requests.size());
		} catch (Exception e) {
			log.error("Customer.listRequests()/GET - error happned while retrieving requests for userId ("+userId+")",e);
		}
		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return "client.listRequests";
	}

	@RequestMapping(value = "/listRequests.htm", method = RequestMethod.POST)
	@Transactional(readOnly = true)
	public String listRequests(
			@ModelAttribute(value = GlobalConstants.REQUEST_SEARCH_CRITERIA) @Valid RequestSearchCriteria searchCriteria,
			BindingResult errors, Model model, HttpServletRequest request, @RequestParam(value = "type") String type) {
		
//		HttpSession session = request.getSession();// should get it from session
//													// when integrating with
//													// login logic,but now for
//													// testing we will add it
//													// here
//		String userId = (String) session
//				.getAttribute(GlobalConstants.USER_NAME_ATTRIBUTE);
		
		boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
		String userId = "";
		if(isCustomer){
			userId = request.getUserPrincipal().getName();
		}else{
			return "redirect:/login.jsp";
		}
		
		List<Request> requests = new ArrayList<Request>();
		try {
			if (errors.hasErrors()) {
				return "client.listRequests";
			}
			searchCriteria = buildRequestId(searchCriteria);
			System.out.println("View Request Id is  "
					+ searchCriteria.getViewRequestId());
			long allRequestsSize = workflowDelegate.getAllRequestsSize(userId,
					false, searchCriteria);
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = allRequestsSize / pageSize;
			if ((allRequestsSize % pageSize) > 0) {
				totalPages++;
			}
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) allRequestsSize);
			searchCriteria.setFirstAndLastPageFlags();
			searchCriteria.setType(type);
			requests = workflowDelegate.getAllRequests(userId, false,
					searchCriteria);
			System.out.println("requests retuned = " + requests.size());
		} catch (Exception e) {
			log.error("Customer.listRequests()/POST - error happned while retrieving requests for userId ("+userId+")",e);
		}
		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return "client.listRequests";
	}

	@Transactional(readOnly = true)
	@RequestMapping(value = "/viewInbox.htm", method = RequestMethod.GET)
	public String viewInbox(Model model, HttpServletRequest request,
			@RequestParam(value = "type") String type) {
		// String userId = "somaya.rayan";//should get it from session
		// when integrating with login logic,but now for testing we will add it
		// here
//		HttpSession session = request.getSession();
//		String userId = (String) session
//				.getAttribute(GlobalConstants.USER_NAME_ATTRIBUTE);
		
		boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
		String userId = "";
		if(isCustomer){
			userId = request.getUserPrincipal().getName();
		}else{
			return "redirect:/login.jsp";
		}
		
		System.out
				.println("inside the viewInbox GET method in Customer controller ");

		// 1- set the default date period
		RequestSearchCriteria searchCriteria = new RequestSearchCriteria();
		Calendar today = Calendar.getInstance();
		today.setTime(new Date());
		searchCriteria.setPageNumber(1);
		// this attribue is added to keep track of which menu item is currently
		// selected!!!!
		searchCriteria.setType(type);

		List<Request> requests = new ArrayList<Request>();
		try {
			long getAllActiveTasksSize = workflowDelegate
					.getAllActiveTasksSize(
							WorkflowDataFields.ProcessName.getPropertyName(),
							userId, false, searchCriteria, false);
			System.out.println("*** getAllActiveTasksSize = "
					+ getAllActiveTasksSize + " ******");
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = getAllActiveTasksSize / pageSize;
			if ((getAllActiveTasksSize % pageSize) > 0) {
				totalPages++;
			}
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) getAllActiveTasksSize);
			searchCriteria.setFirstAndLastPageFlags();
			searchCriteria.setAssending(true);
			System.out.println("*** totalPages = " + totalPages + " ******");
			requests = workflowDelegate.getActiveTasks(searchCriteria,
					WorkflowDataFields.ProcessName.getPropertyName(), userId,
					false, false);
			searchCriteria.setSortField(RequestField.CreationDate.getPropertyName());
		} catch (Exception ex) {
			log.error("Customer.viewInbox()/GET - error happned while retrieving requests for userId ("+userId+")",ex);
		}
		searchCriteria.setStatuses(searchCriteria.getClientStatuses());
		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return "client.viewInbox";
	}

	@RequestMapping(value = "/viewInbox.htm", method = RequestMethod.POST)
	@Transactional(readOnly = true)
	public String viewInbox(
			@ModelAttribute(value = GlobalConstants.REQUEST_SEARCH_CRITERIA) @Valid RequestSearchCriteria searchCriteria,
			BindingResult errors, Model model, HttpServletRequest request, @RequestParam(value = "type") String type) {

		// String userId = "somaya.rayan";//should get it from session
		// when integrating with login logic,but now for testing we will add it
		// here
		//HttpSession session = request.getSession();
		//String userId = (String) session.getAttribute(GlobalConstants.USER_NAME_ATTRIBUTE);
		
		boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
		String userId = "";
		if(isCustomer){
			userId = request.getUserPrincipal().getName();
		}else{
			return "redirect:/login.jsp";
		}
		
		List<Request> requests = new ArrayList<Request>();
		try {
			if (errors.hasErrors()) {
				return "redirect:/client/listRequests.htm";
			}
			searchCriteria = buildRequestId(searchCriteria);
			long getAllActiveTasksSize = workflowDelegate
					.getAllActiveTasksSize(
							WorkflowDataFields.ProcessName.getPropertyName(),
							userId, false, searchCriteria, false);
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = getAllActiveTasksSize / pageSize;
			if ((getAllActiveTasksSize % pageSize) > 0) {
				totalPages++;
			}
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) getAllActiveTasksSize);
			searchCriteria.setFirstAndLastPageFlags();
			searchCriteria.setType(type);
			requests = workflowDelegate.getActiveTasks(searchCriteria,
					WorkflowDataFields.ProcessName.getPropertyName(), userId,
					false, false);
			System.out.println("requests retuned = " + requests.size());
		} catch (Exception e) {
			log.error("Customer.viewInbox()/POST - error happned while retrieving requests for userId ("+userId+")",e);
		}
		searchCriteria.setStatuses(searchCriteria.getClientStatuses());
		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return "client.viewInbox";
	}

	private RequestSearchCriteria buildRequestId(
			RequestSearchCriteria searchCriteria) {
		if (null != searchCriteria) {
			String viewReqId = searchCriteria.getViewRequestId();
			if (null != viewReqId) {
				String[] requestIdData = viewReqId.split("_");
				searchCriteria.setServiceName(requestIdData[0].trim() +  "_" + requestIdData[1].trim());
				searchCriteria.setRequestType(requestIdData[2].trim());
				searchCriteria.setCreationDate(UtilCommon
						.getDateFromString(requestIdData[3].trim()));
				searchCriteria.setRequestId(Long.parseLong(requestIdData[4]));
			}
		}
		return searchCriteria;
	}

	@RequestMapping(value = "/edit.htm", method = RequestMethod.POST)
	public String edit(
			@ModelAttribute(value = GlobalConstants.OFC_REQUEST_MODEL) OFCRequestCreation ofcRequestCreation) {
		if (ofcRequestCreation.getStatus().equals(
				RequestStatus.Return_For_Update.name())) {

		}
		return "client.viewDetails";
	}

	@Transactional
	@RequestMapping(value = "/cancel.htm", method = RequestMethod.GET)
	public String cancelRequest(
			@RequestParam(value = GlobalConstants.REQUEST_ID) String requestId,
			HttpServletRequest request,
			@RequestHeader(value = "referer", required = false) String referer) {
		// TODO
		// When integrate with TSC, when changing
		boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
		String username = "";
		if(isCustomer){
			username = request.getUserPrincipal().getName();
		}else{
			return "redirect:/login.jsp";
		}
		
		try {
			workflowDelegate.cancelRequest(Long.parseLong(requestId), username,
					false);
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.cancel", null, RequestContextUtils.getLocale(request)));
		} catch (NumberFormatException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Customer.cancelRequest() - number format exception while cancel request ("+requestId+")",e);
		} catch (InvalidInputException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Customer.cancelRequest() - Invalid input provided while cancel request ("+requestId+")",e);
		} catch (CommunicationException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			UtilCommon.rollbackTransaction();
			//ExceptionHandlerHelper.handleException(e);
			log.error("Customer.cancelRequest() - WF error occurred while cancel request ("+requestId+")",e);
		}
		catch (IMSException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			UtilCommon.rollbackTransaction();
			//ExceptionHandlerHelper.handleException(e);
			log.error("Customer.cancelRequest() - IMS error occurred while cancel request ("+requestId+")",e);
		}
		catch (FNPServiceExpcetion e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			ExceptionHandlerHelper.handleException(e);
			log.error("Customer.cancelRequest() - FNP error occurred while cancel request ("+requestId+")",e);
		}
		if(referer == null){
			referer = "listRequests.htm?type=" + request.getParameter("type");
		}else if(!referer.contains("type")){
			referer = referer.concat("?type=" + request.getParameter("type"));
		}
		return "redirect:" + referer;
	}

	@Transactional
	@RequestMapping(value = "/viewDetails.htm", method = RequestMethod.POST)
	public String manipulateRequest(Model model,
			@ModelAttribute(value = GlobalConstants.OFC_REQUEST_MODEL) OFCRequestCreation ofcRequestModel,
			BindingResult errors,
			@RequestHeader(value = "referer", required = false) String referer,
			HttpServletRequest request, Locale locale) {
		
		String action = request.getParameter("action");
		
		if (null != action && null != RequestAction.getRequestAction(action)) {
			RequestAction requestAction = RequestAction
					.getRequestAction(action);
			// TODO
			// Changing after authantication integration
			boolean isCustomer = request.isUserInRole(GlobalConstants.CUSTOMER_ROLE);
			String username = "";
			if(isCustomer){
				username = request.getUserPrincipal().getName();
			}else{
				return "redirect:/login.jsp";
			}
			String successMessage = "success.request.info.edit";
			List<OFCDocument> documents = ofcRequestModel.getDocuments();
			try {
				boolean isReseat = false;
				if (requestAction.equals(RequestAction.PaymentDone)
						|| requestAction.equals(RequestAction.AdditionalPaymentDone)) {
					errors = validateUploadedDocuments(ofcRequestModel.getMultipartFiles(), ofcRequestModel.getDocuments(), errors, ofcRequestModel.getStatus());
					isReseat = true;
					if (null != documents) {
						for (int i = 0; i < documents.size(); i++) {
							String englishName = documents.get(i).getDocumentType().getEnglishName();
							String arabicName = documents.get(i).getDocumentType().getArabicName();
							if ((null != englishName && englishName.equals(messageSource.getMessage("document.name.paymentReceipt", null, locale))) || (null != arabicName && arabicName.equals(messageSource.getMessage("document.name.paymentReceipt", null, locale)))){	
								break;
							}else{
								if (i < (documents.size() - 1)) {
									continue;
								}
								errors.reject("error.ofcRequestModel.documentType.reset");
								prepareModelJson(model, ofcRequestModel.getStatus());
								prepareModelLocations(request, ofcRequestModel);
								return "client.viewDetails";
							}
						}

					} else if (null == documents) {
						errors.reject("error.ofcRequestModel.documentType.reset");
						prepareModelLocations(request, ofcRequestModel);
						prepareModelJson(model, ofcRequestModel.getStatus());
						return "client.viewDetails";
					}
				} else if (requestAction.equals(RequestAction.Resubmit)) {
					errors = validateCreateRequest(ofcRequestModel, errors, locale);
				} else if (requestAction.equals(RequestAction.REINSPECTION_REQUIRED)) {
					List<Comment> imsComments = ofcRequestModel.getComments();
					if(null != imsComments){
						for(Comment comment : imsComments){
							if(null == comment.getReply() || comment.getReply().isEmpty()){
								errors.reject("error.ofcRequestModel.nonComplianceComment.reply");
							}
						}
					}
				} 
				
				if (errors.hasErrors()) {
					prepareModelJson(model, ofcRequestModel.getStatus());
					if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
						ofcRequestModel.setAmendmentTypes(AmendmentType.values());
					}
					prepareModelLocations(request, ofcRequestModel);
					return "client.viewDetails";
				}

				OFCRequest ofcRequest = workflowDelegate.getDetails(ofcRequestModel.getId(), username, false);

				// upload files
				List<MultipartFile> files = ofcRequestModel.getMultipartFiles();
				String mailBody = "";
				File receiptFile = null;
				if (null != files) {
					for (int i = 0; i < files.size(); i++) {
						String englishName = documents.get(i).getDocumentType().getEnglishName();
						String arabicName = documents.get(i).getDocumentType().getArabicName();
						FileOutputStream fos = null;
						Date currentDate = new Date();
						try {
							if (null != files.get(i)) {
								// TODO after integration with TSC change
								// uploadedFolder
								// path to take Trakhes ID
								File uploadedFolder = new File(
										generalMap
												.get("documentLocation")
												+ "/"
												+ ofcRequest.getTrakheesId()
												+ "/"
												+ ofcRequest.getUserId() + "/" + ofcRequest.getProcessId());
								if (!uploadedFolder.exists()) {
									uploadedFolder.mkdirs();
								}
								File file = new File(uploadedFolder, files.get(
										i).getOriginalFilename());
								if (file.exists()) {
									file.delete();
									
								}
								file.createNewFile();
								fos = new FileOutputStream(file);
								fos.write(files.get(i).getBytes());
								ofcRequestModel
										.getDocuments()
										.get(i)
										.setDocumentName(
												files.get(i)
														.getOriginalFilename());
								ofcRequestModel
										.getDocuments()
										.get(i)
										.setDocumentLocation(
												ofcRequestModel.getTrakheesId()
														+ "/"
														+ ofcRequest
																.getUserId()
																 + "/" + ofcRequest.getProcessId()
														+ "/"
														+ ofcRequestModel
																.getDocuments()
																.get(i)
																.getDocumentName());
								if (null == ofcRequestModel.getDocuments()) {
									ofcRequestModel
											.setDocuments(new ArrayList<OFCDocument>());
								}
								//mailBody += file.getAbsolutePath() + "<br>";
								//mailBody += "<a href=\"common/download.htm?fileId="+ofcRequest.getDocuments().get(i).getId() + "\""+ofcRequest.getDocuments().get(i).getDocumentName()+"</a><br>";
								
								if (requestAction.equals(RequestAction.PaymentDone)
										|| requestAction.equals(RequestAction.AdditionalPaymentDone)) {
									
									if ((null != englishName && englishName.equals(messageSource.getMessage("document.name.paymentReceipt", null, locale))) || (null != arabicName && arabicName.equals(messageSource.getMessage("document.name.paymentReceipt", null, locale)))) {
										receiptFile = file;
									}
								}
							}

						} catch (Exception ioe) {
							System.out.println("File Upload Unsuccessful.");
							log.error("Customer.manipulateRequest() - exception occurred while manipulate request ("+ofcRequest.getId()+")",ioe);
						} finally {
							if (null != fos) {
								fos.close();
							}

						}
					}
					
					
				}
				// get the documents that has no ID here from the Model List.
				List<OFCDocument> tempDocuments = new ArrayList<OFCDocument>();
				for(int getEmptyId=0;getEmptyId<documents.size();getEmptyId++){
					if(documents.get(getEmptyId).getId()==0){
						tempDocuments.add(documents.get(getEmptyId));
					}
				}
				// To remove deleted javascript document
				if (null != documents) {
					for (OFCDocument ofcDocument : ofcRequestModel
							.getDocuments()) {
						if (ofcDocument == null
								|| (ofcDocument.getDocumentLocation() == null
										&& ofcDocument.getDocumentName() == null
										&& ofcDocument.getDocumentType() == null && ofcDocument
										.getId() == 0)) {
							ofcRequestModel.getDocuments().remove(ofcDocument);
						}
					}
				}
				List<Comment> reqComments = null;
				List<Comment> originalComments = ofcRequest.getComments();
				if(requestAction.equals(RequestAction.REINSPECTION_REQUIRED)){
					if(ofcRequestModel.getComments() != null && originalComments != null){
						reqComments = new ArrayList<Comment>(originalComments);
						for(int i = 0;i<ofcRequestModel.getComments().size();i++){
							if(!ofcRequestModel.getComments().get(i).getReplied()){
								reqComments.get(i).setReply(ofcRequestModel.getComments().get(i).getReply());
								reqComments.get(i).setReplied(true);
							}
						}
					}
				}
				
				workflowDelegate.getMapper().map(ofcRequestModel, ofcRequest);
				if (requestAction.equals(RequestAction.PaymentDone)) {
					ofcRequest.setStatus(RequestStatus.Payment_Done);
				} else if (requestAction.equals(RequestAction.AdditionalPaymentDone)) {
					ofcRequest.setStatus(RequestStatus.Additional_Payment_Done);
				} else if (requestAction.equals(RequestAction.Resubmit)) {
					ofcRequest.setStatus(RequestStatus.Resubmitted);
				}else if (requestAction.equals(RequestAction.REINSPECTION_REQUIRED)) {
					String status = null;
					try {
						status = imsDelegate.setIMSCustomerReply(ofcRequest.getImsLogId(), reqComments);
						ofcRequest.setComments(reqComments);
					} catch(IMSException e){
						log.error("Customer.manipulateRequest() - error occurred while setting customer reply for ims log id : "+ofcRequest.getImsLogId(),e);
					}
					
					if("Y".equals(status)){
						ofcRequest.setStatus(RequestStatus.Comments_Replied);
						requestAction = RequestAction.REPLY_COMMENTS;
					}else{
						if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
							ofcRequestModel.setAmendmentTypes(AmendmentType.values());
						}
						errors.reject("error.ofcRequestModel.exception");
						prepareModelJson(model, ofcRequestModel.getStatus());
						prepareModelLocations(request, ofcRequestModel);
						return "client.viewDetails";
					}
				}
				//List<OFCDocument> oldSavedDocuments = ofcRequest.getDocuments();
				
				ofcRequest.setUserId(username);
				ofcRequest = updateRequest(ofcRequest);
				ofcRequest.setDocuments(documents);
				
				boolean result = workflowDelegate.manipulateRequest(ofcRequest, username, false, requestAction);
				if(result == false){
					throw new WorkFlowException();
				}
				String URL= "";
				String name = request.getServerName();
				int port = request.getServerPort();
				String ctx = request.getContextPath();
				
				URL = "http://"+name+(port!=0? ":"+port:"")+ctx;
				
				boolean changedList = tempDocuments.size()!=0;
				if(changedList){
					//Sending Link Email
					for(int doc =tempDocuments.size()-1; doc>=0;doc--){
						for(int reqDoc=ofcRequest.getDocuments().size()-1;reqDoc>=0;reqDoc--){
							if(ofcRequest.getDocuments().get(reqDoc).getDocumentName().equalsIgnoreCase(tempDocuments.get(doc).getDocumentName()) && ofcRequest.getDocuments().get(reqDoc).getDocumentType().getId()== tempDocuments.get(doc).getDocumentType().getId()){
								mailBody += "<a href=\""+URL+"/common/download.htm?fileId="+ofcRequest.getDocuments().get(reqDoc).getId() + "\">"+ofcRequest.getDocuments().get(reqDoc).getDocumentName()+"</a><br>";
								break;
							}
						}
					}
				}
				
				Map<String, String> mailMap = new HashedMap();
				mailMap.put(GlobalConstants.CUSTOMER_NAME, ofcRequest.getUserId());
				mailMap.put(GlobalConstants.CUSTOMER_COMPANY, ofcRequestModel.getCompanyNameEnglish());
				mailMap.put(GlobalConstants.DOCUMENT_URL, mailBody);
				mailMap.put(GlobalConstants.REQUEST_NO, UtilCommon.getFormmattedRequestId(ofcRequest.getService().getName(), ofcRequest.getType().name(), ofcRequest.getId(), ofcRequest.getCreationDate()));
				try {
					if (!mailBody.isEmpty()) {
						
						mailUtility.sendMail(null, mailMap, null, GlobalConstants.DOCUMENT_TEMPLATE);


					}
					if(isReseat){
						if (requestAction.equals(RequestAction.PaymentDone)){
							mailMap.put(GlobalConstants.ADVICE_NUMBER, ofcRequest.getFnpList().get(0).getPaymentNumber());
						}else if (requestAction.equals(RequestAction.AdditionalPaymentDone)){
							mailMap.put(GlobalConstants.ADVICE_NUMBER, ofcRequest.getFnpList().get(1).getPaymentNumber());
						}
						mailMap.put(GlobalConstants.TRAKHEES_ID, ofcRequest.getTrakheesId());
						mailUtility.sendMail(null, mailMap, receiptFile, GlobalConstants.RECEIPT_TEMPLATE);
					}
				} catch (SystemException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage(successMessage, null, RequestContextUtils.getLocale(request)));
			} catch (InvalidInputException e) {
				if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
					ofcRequestModel.setAmendmentTypes(AmendmentType.values());
				}
				log.error("Customer.manipulateRequest() - invalid input provided while manipulate request ("+request+")",e);
				errors.reject("error.ofcRequestModel.exception");
				prepareModelJson(model, ofcRequestModel.getStatus());
				prepareModelLocations(request, ofcRequestModel);
				UtilCommon.rollbackTransaction();
				return "client.viewDetails";
			} catch (WorkFlowException e) {
				if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
					ofcRequestModel.setAmendmentTypes(AmendmentType.values());
				}
				log.error("Customer.manipulateRequest() - workflow exception while manipulate request ("+request+")",e);
				errors.reject("error.generic");
				prepareModelJson(model, ofcRequestModel.getStatus());
				prepareModelLocations(request, ofcRequestModel);
				UtilCommon.rollbackTransaction();
				return "client.viewDetails";
			} catch (CommunicationException e) {
				if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
					ofcRequestModel.setAmendmentTypes(AmendmentType.values());
				}
				log.error("Customer.manipulateRequest() - WF error while manipulate request ("+request+")",e);
				ExceptionHandlerHelper.handleException(e);
				errors.reject("error.ofcRequestModel.exception");
				prepareModelLocations(request, ofcRequestModel);
				prepareModelJson(model, ofcRequestModel.getStatus());
				UtilCommon.rollbackTransaction();
				return "client.viewDetails";
			} catch (IOException e) {
				if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
					ofcRequestModel.setAmendmentTypes(AmendmentType.values());
				}
				log.error("Customer.manipulateRequest() - IO error while manipulate request ("+request+")",e);
				errors.reject("error.ofcRequestModel.exception");
				prepareModelJson(model, ofcRequestModel.getStatus());
				prepareModelLocations(request, ofcRequestModel);
				UtilCommon.rollbackTransaction();
				return "client.viewDetails";
			}
		}
		return "redirect:viewInbox.htm?type=inbox";
	}
	
	
	private OFCRequest updateRequest(OFCRequest ofcRequest){
		ofcRequest.setExecuter(UserType.User);
		ofcRequest.setProcessingDate(new Date());

		OFCRequestHistory history = new OFCRequestHistory();
		workflowDelegate.getMapper().map(ofcRequest, history);
		history.setOfficerComments("");
		ofcRequest.getOfcHistory().add(history);
		
		return ofcRequest;
	}

}
